#include "widget.h"
#include <qpainter.h>
#include <qpixmap.h>
#include <qbrush.h>
#include <qevent.h>
#include <qcolor.h>
#include <qmessagebox.h>
#include <qtextbrowser.h>
#include <qfile.h>
#include <qdatastream.h>
#include <qfiledialog.h>
#include "timer.h"
#include "gamer.h"
#include "comai.h"
#include "comai2.h"
#include "comai3.h"
#include <qdebug.h>
#include "map.h"
#include "replay.h"
#include "startsettings.h"
#include "vssocket.h"
#include "talkdialog.h"
#define NOTSIDE(a) ((a)!=0 && (a)!=5)
const int VERSION=0xabcd0078;
const int D=46;
const int N=6;
const QColor COLOR(109,137,248),COLOR1(11,53,221),COLOR2(197,207,252);
Widget::Widget(QWidget *parent) :
	QWidget(parent),map(420,420)
{
	a=0;
	totalstep=0;
	draw();
	selected=0;
	started=0;
	game=0;
	waiting=0;
	this->setMouseTracking(1);
	r=new Replay(this);
	connect(r,SIGNAL(frist()),this,SLOT(onfrist()));
	connect(r,SIGNAL(last()),this,SLOT(onlast()));
	connect(r,SIGNAL(next()),this,SLOT(onnext()));
	connect(r,SIGNAL(prev()),this,SLOT(onprev()));
}
void Widget::paintEvent(QPaintEvent *)
{
	QPainter p(this);
	int i,j;
	p.translate(2,2);
	p.setRenderHint(QPainter::Antialiasing,true);
	p.drawPixmap(0,0,map);
	if(waiting || !started) return;
	p.setPen(Qt::white);
	p.setBrush(QBrush(QColor(0,255,0,25)));
	p.drawRect(mj*D+1.5*D+2,mi*D+1.5*D+2,D,D);
	if(selected)
	{
        p.setPen(Qt::white);
		p.setBrush(QBrush(QColor(0,255,0,0)));
		p.drawRect(tj*D+1.5*D+2,ti*D+1.5*D+2,D,D);
		if(NOTSIDE(ti))
		{
			a->eat(ti,tj,0,1,i,j);
			if(i>=0)
			{
				p.setPen(Qt::blue);
				p.setBrush(QBrush(Qt::blue));
				p.drawEllipse(j*D+20+1.5*D+2,i*D+20+1.5*D+2,D-40,D-40);
			}
			a->eat(ti,tj,0,-1,i,j);
			if(i>=0)
			{
				p.setPen(Qt::blue);
				p.setBrush(QBrush(Qt::blue));
				p.drawEllipse(j*D+20+1.5*D+2,i*D+20+1.5*D+2,D-40,D-40);
			}
		}
		if(NOTSIDE(tj))
		{
			a->eat(ti,tj,1,0,i,j);
			if(i>=0)
			{
				p.setPen(Qt::blue);
				p.setBrush(QBrush(Qt::blue));
				p.drawEllipse(j*D+20+1.5*D+2,i*D+20+1.5*D+2,D-40,D-40);
			}
			a->eat(ti,tj,-1,0,i,j);
			if(i>=0)
			{
				p.setPen(Qt::blue);
				p.setBrush(QBrush(Qt::blue));
				p.drawEllipse(j*D+20+1.5*D+2,i*D+20+1.5*D+2,D-40,D-40);
			}
		}
		bool e=(a->get(mi,mj)!=0);
		if(a->move(ti,tj,mi,mj))
		{
			for(i=0;i<6;i++)
				for(j=0;j<6;j++)
				{
					if(a->move(i,j,mi,mj))
					{
						p.setPen(Qt::red);
						p.setBrush(QBrush(Qt::red));
						p.drawEllipse(j*D+20+1.5*D+2,i*D+20+1.5*D+2,D-40,D-40);
						a->umove(i,j,mi,mj,1);
					}
			}
			a->umove(ti,tj,mi,mj,e);
		}
	}
}
void Widget::draw()
{
	QPainter p(&map);
	p.translate(2,2);
	p.setRenderHint(QPainter::Antialiasing,true);
	QString s;
	int i;
	p.setPen(COLOR);
	p.setBrush(COLOR);
	p.drawRect(-2,-2,420,420);
	p.setPen(COLOR1);
	p.drawEllipse(0,0,4*D,4*D);
	p.drawEllipse(5*D,0,4*D,4*D);
	p.drawEllipse(0,5*D,4*D,4*D);
	p.drawEllipse(5*D,5*D,4*D,4*D);
	p.setPen(COLOR2);
	p.drawEllipse(D,D,2*D,2*D);
	p.drawEllipse(5*D+D,D,2*D,2*D);
	p.drawEllipse(D,5*D+D,2*D,2*D);
	p.drawEllipse(5*D+D,5*D+D,2*D,2*D);
	p.setPen(Qt::black);
	p.drawRect(2*D,2*D,5*D,5*D);
	for (i=0;i<N;i++)
	{
		if (i==1||i==4) p.setPen(COLOR2);
		else if (i==2||i==3) p.setPen(COLOR1);
		else p.setPen(Qt::black);
		p.drawLine(2*D,i*D+2*D,N*D+D,i*D+2*D);
		p.drawLine(i*D+2*D,2*D,i*D+2*D,N*D+D);
	}
	p.setBrush(QBrush(Qt::black));
	if(a==0)
	{
		return;
	}
	int j,ei,ej;
	p.setPen(QPen(Qt::black));
	for(i=0;i<N;i++)
		for(j=0;j<N;j++)
		{
			if(a->get(i,j)==1)
			{
				p.setBrush(QBrush(Qt::black));
				p.drawEllipse(j*D+6+1.5*D,i*D+6+1.5*D,D-12,D-12);
			}else if(a->get(i,j)==2)
			{
				p.setBrush(QBrush(Qt::white));
				p.drawEllipse(j*D+6+1.5*D,i*D+6+1.5*D,D-12,D-12);
			}
		}

	if(!steps.isEmpty())
	{
		Steps s=steps.last();
		p.setPen(Qt::red);
		p.setBrush(QBrush(Qt::red));
		p.drawEllipse(s.ej()*D+4+1.5*D,s.ei()*D+4+1.5*D,D-8,D-8);
		p.setPen(QColor(0,0,0,80));
		if(a->get(s.ei(),s.ej())==2)
		{
			p.setBrush(QBrush(QColor(255,255,255,80)));
			p.drawEllipse(s.sj()*D+6+1.5*D,s.si()*D+6+1.5*D,D-12,D-12);
			p.setPen(Qt::black);
			p.setBrush(QBrush(QColor(255,255,255)));
			p.drawEllipse(s.ej()*D+6+1.5*D,s.ei()*D+6+1.5*D,D-12,D-12);
		}
		else
		{
			p.setBrush(QBrush(QColor(0,0,0,80)));
			p.drawEllipse(s.sj()*D+6+1.5*D,s.si()*D+6+1.5*D,D-12,D-12);
			p.setPen(Qt::black);
			p.setBrush(QBrush(QColor(0,0,0)));
			p.drawEllipse(s.ej()*D+6+1.5*D,s.ei()*D+6+1.5*D,D-12,D-12);
		}
	}
	for(i=0;i<6;i++)
		for(j=0;j<6;j++)
			if(a->get(i,j)==1+color)
			{
				if(NOTSIDE(i))
				{
					a->eat(i,j,0,1,ei,ej);
					if(ei>=0)
					{
						p.setPen(Qt::yellow);
						p.setBrush(QBrush(Qt::yellow));
						p.drawEllipse(ej*D+20+1.5*D,ei*D+20+1.5*D,D-40,D-40);
					}
					a->eat(i,j,0,-1,ei,ej);
					if(ei>=0)
					{
						p.setPen(Qt::yellow);
						p.setBrush(QBrush(Qt::yellow));
						p.drawEllipse(ej*D+20+1.5*D,ei*D+20+1.5*D,D-40,D-40);
					}
				}
				if(NOTSIDE(j))
				{
					a->eat(i,j,1,0,ei,ej);
					if(ei>=0)
					{
						p.setPen(Qt::yellow);
						p.setBrush(QBrush(Qt::yellow));
						p.drawEllipse(ej*D+20+1.5*D,ei*D+20+1.5*D,D-40,D-40);
					}
					a->eat(i,j,-1,0,ei,ej);
					if(ei>=0)
					{
						p.setPen(Qt::yellow);
						p.setBrush(QBrush(Qt::yellow));
						p.drawEllipse(ej*D+20+1.5*D,ei*D+20+1.5*D,D-40,D-40);
					}
				}
			}
	QList<Steps>::iterator itr;
	QString s2,s1;
	itr=steps.begin();
	i=1;
	for(;itr!=steps.end();itr++,i++)
	{
		s1.sprintf("%d:(%d,%d)->(%d,%d)\n",i,(*itr).si(),(*itr).sj(),(*itr).ei(),(*itr).ej());
		s2+=s1;
	}
	i--;
	viewer->setText(s2);
	repaint();
}
void Widget::mousePressEvent(QMouseEvent *e)
{
	if(!started || waiting)
		return;
	if(e->button()==Qt::RightButton)
	{
		selected=0;
		repaint();
	}
	else if(e->button()==Qt::LeftButton)
	{
		if(selected)
		{
			if(a->get(mi,mj)==2-color)
			{
				ti=mi;tj=mj;
				repaint();
			}else if(a->move(ti,tj,mi,mj))
			{
				steps.append(Steps(ti,tj,mi,mj));
				totalstep++;
				selected=0;
				draw();
				repaint();
				if(winorlose())
				{
					wol(1);
					if(StartSettings::gameType == StartSettings::netGame)
						StartSettings::socket->sendStepMessage(Steps(ti,tj,mi,mj));
				}else
				{
					if(StartSettings::gameType==StartSettings::twoplayers)
					{
						color=1-color;
						emit isReady(1);
						emit changetimer();
					}else if(StartSettings::gameType==StartSettings::singleGame)
					{
						waiting=1;
						emit isReady(0);
						emit changetimer();
						viewer->setText(tr("Waiting...\n"));
						game->set(*a);
						game->start();
					}else if(StartSettings::gameType == StartSettings::netGame)
					{
						waiting=1;
						emit isReady(0);
						emit changetimer();
						viewer->setText(tr("Waiting...\n"));
						qDebug()<<"send";
						StartSettings::socket->sendStepMessage(Steps(ti,tj,mi,mj));
					}
				}
			}
		}else
		{
			if(a->get(mi,mj)==2-color)
			{
				selected=1;
				ti=mi;tj=mj;
				repaint();
			}
		}
	}
}
Widget::~Widget()
{
	if(game)
		delete game;
	if(a)
		delete a;
}
void Widget::start()
{
	if(a)
	{
		delete a;
	}
	a=new Map;
	steps.clear();
	totalstep=0;selected=0;
	color=StartSettings::playerColor;replay=0;r->hide();
	datetime=datetime.currentDateTime();
	datetime.toString("yyyy-MM-dd hh:mm:ss");
	if(game)
	{
		game->terminate();
		game->wait();
		disconnect(game,SIGNAL(move(int,int,int,int)),this,SLOT(over(int,int,int,int)));
		delete game;
	}

	emit isReady(0);
	mi=mj=0;
	waiting=0;
	draw();
	repaint();
	//if(diff==1) game=new ComAI2(color,13);
	if(StartSettings::gameType==StartSettings::singleGame)
	{
		if(StartSettings::diff==1) game=new ComAI2(color,16);
		else if(StartSettings::diff==2) game=new ComAI2(color,17);
		else game=new ComAI2(color,18);
		connect(game,SIGNAL(move(int,int,int,int)),this,SLOT(over(int,int,int,int)));
		connect(game,SIGNAL(sendMsg(QString)),StartSettings::talkDialog,SLOT(addMsg(QString)));
	}
	started=1;
	this->repaint();
	if(color==0 && StartSettings::gameType == StartSettings::singleGame)
	{
		waiting=1;
		emit isReady(0);
		emit changetimer();
		viewer->setText(tr("Waiting...\n"));
		game->set(*a);
		game->start();
	}
	if(StartSettings::gameType==StartSettings::twoplayers)
		emit isReady(1);
	if(StartSettings::gameType == StartSettings::netGame)
	{
		connect(StartSettings::socket,SIGNAL(moved(int,int,int,int)),this,SLOT(over(int,int,int,int)));
		connect(StartSettings::socket,SIGNAL(disconnected()),this,SLOT(error()));

	}
	if(color==0 && StartSettings::gameType == StartSettings::netGame)
	{

		waiting=1;
		emit isReady(0);
		emit changetimer();
		viewer->setText(tr("Waiting...\n"));
	}
}
void Widget::over(int si,int sj,int ei,int ej)
{
	if(!waiting) return;
	if(a->get(si,sj)!=color+1 || !a->move(si,sj,ei,ej))
	{
		qDebug()<<"error"<<si<<sj<<ei<<ej;
	}
	totalstep++;
	if(totalstep>1) emit isReady(1);
	steps.append(Steps(si,sj,ei,ej));
	waiting=0;
	emit changetimer();
	//a[i][j]=(totalstep%4)/2+1;
	draw();repaint();
	if(winorlose())
	{
		wol(0);
	}
}
void Widget::setVT(QTextBrowser *p, Timer *ta, Timer *tb)
{
	viewer=p;
	t1=ta;
	t2=tb;
}
void Widget::onundo()
{
	if(StartSettings::gameType==StartSettings::singleGame)
	{
		if(waiting || !started) return;
		if(totalstep==0 || totalstep==1 && color==0)
		{
			emit isReady(0);
			return;
		}
		if(totalstep==1) steps.pop_back(),totalstep--;
		else steps.pop_back(),steps.pop_back(),totalstep-=2;
		reset();
		if(totalstep==0 ||(totalstep==1 && color==0))
			emit isReady(0);
	}
	if(StartSettings::gameType==StartSettings::twoplayers)
	{
		if(totalstep==0)
		{
			emit isReady(0);
			return;
		}
		steps.pop_back(),totalstep--;
		if(totalstep==0)
			emit isReady(0);
		emit changetimer();
		reset();
	}
	draw();
	repaint();
}
void Widget::mouseMoveEvent(QMouseEvent *e)
{
	mi=(e->y()-1.5*D)/D;
	mj=(e->x()-1.5*D)/D;
	if(mi>=N) mi=N-1;
	if(mi<0) mi=0;
	if(mj>=N) mj=N-1;
	if(mj<0) mj=0;
	repaint();
}
void Widget::onload()
{
	int v,ta,tb;
	QString s;
	s=QFileDialog::getOpenFileName(0,tr("Choose a file"),"/","saved files (*.c6s)");
	if(s.isEmpty())
	{
		QMessageBox::warning(0,tr("Error"),tr("No file loaded"));
		return;
	}
	started=0;
	isReady(0);
	emit stoptimer();
	if(game)
	{
		game->terminate();
		game->wait();
		disconnect(game,SIGNAL(ok()),this,SLOT(over()));
		delete game;game=0;
	}
	QFile f(s);

	if(f.open(QIODevice::ReadOnly))
	{
		QDataStream in(&f);
		in>>v;
		if(v!=VERSION)
		{
			QMessageBox::warning(0,tr("Error"),tr("This file is not for this version."));
			return;
		}
		in>>color>>ta>>tb;
		t1->setTime(ta);
		t2->setTime(tb);
		in>>(steps);
		totalstep=steps.length();
		r->show();replay=1;
		reset();
		draw();
		repaint();
	}else
		QMessageBox::warning(0,tr("Error"),tr("Cannot read this file."));
}
void Widget::onsave()
{

	QString s=QFileDialog::getSaveFileName(0,tr("Choose a file"),"/","saved files (*.c6s)");
	if(s.isEmpty())
	{
		QMessageBox::warning(0,tr("Error"),tr("No file saved."));
		return;
	}
	QFile file(s);
	if(!file.open(QIODevice::WriteOnly))
	{
		QMessageBox::warning(0,tr("Error"),tr("Cannot write to this file."));
		return;
	}
	QDataStream out(&file);
	out<<VERSION<<color<<t1->getTime()<<t2->getTime()<<steps;
	file.close();
}
void Widget::wol(bool pw)
{
	emit isReady(0);
	QString s;
	s="autosave"+datetime.toString("yyyyMMdd")+".c6s";
	QFile file(s);
	if(!file.open(QIODevice::WriteOnly))
		return;
	QDataStream out(&file);
	out<<VERSION<<color<<t1->getTime()<<t2->getTime()<<steps;
	file.close();
	started=0;
	emit stoptimer();
	if(pw)
	{
		QMessageBox::information(0,tr("You win"),tr("Congratulations!\nYon win!"));
	}
	else
	{
		QMessageBox::information(0,tr("You lose"),tr("You lose!"));
	}
	r->show();
	replay=1;
}
bool Widget::winorlose()
{
	/*int t[3]={0,0,0},i,j;
	for(i=0;i<6;i++)
		for(j=0;j<6;j++)
		{
			t[a->get(i,j)]++;
		}*/
	if(a->gett(1)==0 || a->gett(2)==0)	return 1;
	return 0;
}
void Widget::reset()
{
	QList<Steps>::iterator itr=steps.begin();
	int i=1;
	if(a) delete a;
	a=new Map;
	for(;itr!=steps.end();itr++,i++)
	{
		a->move((*itr).si(),(*itr).sj(),(*itr).ei(),(*itr).ej());
	}
}
void Widget::onfrist()
{
	if(!replay)
		return;
	steps.append(steps2);
	steps2.clear();
	steps2.append(steps);
	steps.clear();
	reset();
	draw();
	repaint();
}
void Widget::onlast()
{
	if(!replay)
		return;
	steps.append(steps2);
	steps2.clear();
	reset();
	draw();
	repaint();
}
void Widget::onprev()
{
	if(!replay || steps.isEmpty())
		return;
	steps2.push_front(steps.last());
	steps.pop_back();
	reset();
	draw();
	repaint();
}
void Widget::onnext()
{
	if(!replay || steps2.isEmpty())
		return;
	steps.push_back(steps2.first());
	steps2.pop_front();
	reset();
	draw();
	repaint();
}
void Widget::error()
{
	QMessageBox::warning(this,tr("error"),tr("Player is disconnected"));
	emit isReady(0);
	QString s;
	s="autosave"+datetime.toString("yyyyMMdd")+".c6s";
	QFile file(s);
	if(!file.open(QIODevice::WriteOnly))
		return;
	QDataStream out(&file);
	out<<VERSION<<color<<t1->getTime()<<t2->getTime()<<steps;
	file.close();
	started=0;
	emit stoptimer();
	r->show();
	replay=1;
}
